home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- // FILENAME: BBC.m
- // SUMMARY: Implementation of a Billiard-Ball Computation Annotation
- // SUPERCLASS: Object
- // INTERFACE: None
- // PROTOCOLS: <DocNotification,Annotation,Tool,ASCIISupport>
- // AUTHOR: Rohit Khare
- // COPYRIGHT: (c) 1994 California Institure of Technology, eText Project
- // COPYRIGHT: (c) 1992 Rohit Khare (core simulation code)
- ///////////////////////////////////////////////////////////////////////////////
- // DESCRIPTION
- // Separated out model from old BilliardView code.
- ///////////////////////////////////////////////////////////////////////////////
- // HISTORY
- // 05/29/94: Created as an eText Annotation.
- // 1992-93: Developed for CS20ab.
- ///////////////////////////////////////////////////////////////////////////////
-
- #import "BBC.h"
- /* to allow access without out-of-bound errors and allow wrap-around */
- #define state(i,j) (state[(i+vres) %vres][(j+hres)%hres])
- #define oldstate(i,j) (oldstate[(i+vres) %vres][(j+hres)%hres])
-
- @implementation BBC
- + toolAwake:theApp
- {
- char buf[MAXPATHLEN];
- NXBundle *bundle;
- NXImage *theIcon;
-
- bundle = [NXBundle bundleForClass:[BBC class]];
- if ([bundle getPath:buf forResource:"N" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"N"];
- } else {
- NXLogError("Image not found: N");
- }
- if ([bundle getPath:buf forResource:"S" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"S"];
- } else {
- NXLogError("Image not found: S");
- }
- if ([bundle getPath:buf forResource:"E" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"E"];
- } else {
- NXLogError("Image not found: E");
- }
- if ([bundle getPath:buf forResource:"W" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"W"];
- } else {
- NXLogError("Image not found: W");
- }
- if ([bundle getPath:buf forResource:"Trail" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"Trail"];
- } else {
- NXLogError("Image not found: Trail");
- }
- if ([bundle getPath:buf forResource:"Wall" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"Wall"];
- } else {
- NXLogError("Image not found: Wall");
- }
- if ([bundle getPath:buf forResource:"Grid" ofType:"tiff"] ) {
- [[[NXImage alloc] initFromFile:buf] setName:"Grid"];
- } else {
- NXLogError("Image not found: Grid");
- }
- if ( [bundle getPath:buf forResource:"BBC" ofType:"tiff"] ) {
- theIcon = [[NXImage alloc] initFromFile:buf];
- [theIcon setName:"BBC"];
- } else {
- NXLogError("Image not found: BBC");
- theIcon = nil;
- }
- [theApp registerAnnotation: [BBC class]
- name: "BBC"
- RTFDirective: "BBC"
- menuLabel: "Simulations/Insert BBC..."
- menuKey: 0
- menuIcon: (NXImage *) theIcon];
- [theApp registerType:NXCreateFileContentsPboardType("bbc")
- for:[BBC class]];
- return self;
- }
-
- - init
- { char buf[MAXPATHLEN];
- NXRect rt;
-
- [super init];
- state = oldstate = NULL;
- sprintf(buf, "Untitled BBC %d", [NXApp uniqueID]);
- theName = NXUniqueString(buf);
- isAccelerated = NO;
- isEditable = doesShowPath = YES;
- bbcView = [[BilliardView alloc] init];
- [bbcView setAutodisplay:YES];
- [bbcView setBBC:self];
- rt.origin.x = rt.origin.y = 0.0;
- rt.size.width = rt.size.height = 200.0;
- scrollView = [[ScrollView alloc] initFrame:&rt];
- [scrollView setDocView:bbcView];
- [scrollView setCopyOnScroll:YES];
- [[scrollView setVertScrollerRequired:YES] setHorizScrollerRequired:YES];
- dirFwd = YES;
- etDoc = nil;
- hres = 10;
- vres = 10;
- [bbcView setRes:hres :vres];
- return self;
- }
-
- - initFromPboard:thePboard inDoc:theDoc linked:(BOOL) linked
- {
- [self init];
- etDoc = theDoc;
- [etDoc registerNotification:self];
- isLinked = linked;
- if (thePboard != nil) {
- // 2 cases: we have a filename or fcontents on the pboard
- if ([thePboard findAvailableTypeFrom:&NXFilenamePboardType
- num:1])
- {
- char *path;
- int len;
- FILE *infile;
- int i,j;
- char c;
-
- isLinked = linked;
- [thePboard readType:NXFilenamePboardType data:&path length:&len];
- if (index(path, '\t')) *index(path, '\t')=0;
- if (isLinked)
- theName = NXUniqueString(path);
- else theName = NXUniqueString(rindex(path, '/')+1);
- infile = fopen(path,"r");
- fscanf(infile,"Hres %d Vres %d Reps %d\n",&hres,&vres,&i);
- state = malloc(vres* sizeof(char*));
- oldstate = malloc(vres* sizeof(char*));
- i = -1;
- while(++i < vres){
- state[i] = malloc(hres*sizeof(char));
- oldstate[i] = malloc(hres*sizeof(char));
- j = -1;
- while(++j < hres){
- fscanf(infile,"%c", &c);
- switch (c) {
- case 'O':{ state[i][j] = c;
- break;}
- case 'N':{ state[i][j] = c;
- break;}
- case 'S':{ state[i][j] = c;
- break;}
- case 'W':{ state[i][j] = c;
- break;}
- case 'E':{ state[i][j] = c;
- break;}
- case ';':
- case '.':
- default :{ state[i][j] = '.';
- break;}
- }
- }
- fscanf(infile,"%c", &c);
- }
- fclose(infile);
- [thePboard deallocatePasteboardData:path length:len];
- } else if ([thePboard findAvailableTypeFrom:&NXFileContentsPboardType
- num:1]) {
- NXLogError("Hey! BBC found fileContents WITHOUT a filename");
- } else
- NXBeep();
- } else {
- int i,j;
-
- state = malloc(vres * sizeof(char*));
- oldstate = malloc(vres * sizeof(char*));
- i = -1;
- while(++i < vres){
- state[i] = malloc(hres*sizeof(char));
- oldstate[i] = malloc(hres*sizeof(char));
- for(j=0; j<hres; j++) state[i][j] = '.';
- }
- }
- [bbcView setRes:hres :vres];
- if ([bbcView window]) {
- NXRect bbcRt, winRt;
-
- [bbcView getBounds:&bbcRt];
- [[bbcView window] getBounds:&winRt];
- if (bbcRt.size.width > (winRt.size.width - 72.0))
- bbcRt.size.width = (winRt.size.width - 72.0);
- if (bbcRt.size.height > (winRt.size.height - 48.0))
- bbcRt.size.height = (winRt.size.height - 48.0);
- [scrollView sizeTo:bbcRt.size.height :bbcRt.size.width];
- }
- return self;
- }
-
- - free
- {
- int i;
-
- [[NXApp inspector] invalidate];
- [etDoc unregisterNotification:self];
- [scrollView free];
- i = -1;
- while(++i < vres){
- free(state[i]);
- free(oldstate[i]);
- }
- free(state);
- free(oldstate);
- return [super free];
- }
-
- - calcCellSize:(NXSize *)theSize
- {
- NXRect theRect;
-
- [scrollView getBounds:&theRect];
- theSize->width = theRect.size.width;
- theSize->height = theRect.size.height;
- return self;
- }
-
- - highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag { return self;}
-
- - drawSelf:(const NXRect *)cellFrame inView:controlView
- {
- if ([scrollView superview] == NULL) [controlView addSubview:scrollView];
- [scrollView setBackgroundGray:NX_WHITE];
- [scrollView moveTo:cellFrame->origin.x :cellFrame->origin.y];
- [scrollView display];
- return self;
- }
-
- - (BOOL) trackMouse:(NXEvent *)theEvent inRect:(const NXRect *)cellFrame
- ofView:controlView
- {
- // does this ever get called at all? is the View higher in Responder ch?
- [[NXApp inspector] inspect:[[BBCUI new] setBBC:self]];
- return YES;
- }
-
- - (NXAtom) name {return theName;}
- - (char *) filename {return theName;} // this doesn't work yet
- - (BOOL) doesShowPath {return doesShowPath;}
- - (BOOL) isAccelerated {return isAccelerated;}
- - (BOOL) isEditable {return isEditable;}
- - (int) hres {return hres;}
- - (int) vres {return vres;}
- - (char **) state {return state;}
- - setName:(NXAtom) newName {theName = newName; return self;}
- - setShowPath:(BOOL) newState {doesShowPath = newState; return self;}
- - setAccelerated:(BOOL) newState {isAccelerated = newState; return self;}
- - setEditable:(BOOL) newState {isEditable = newState; return self;}
- - setRes:(int)h :(int)v
- {
- char **newstate, **newoldstate;
- int i,j;
-
- newstate = malloc(v * sizeof(char*));
- newoldstate = malloc(v * sizeof(char*));
- i = -1;
- while(++i < v){
- newstate[i] = malloc(h*sizeof(char));
- newoldstate[i] = malloc(h*sizeof(char));
- for(j=0; j<h; j++){
- if ((i < vres) && (j < hres))
- newstate[i][j] = state[i][j];
- else newstate[i][j] = '.';
- }
- }
-
- i = -1;
- while(++i < vres){
- free(state[i]);
- free(oldstate[i]);
- }
- free(state);
- free(oldstate);
- state = newstate;
- oldstate = newoldstate;
- hres = h;
- vres = v;
- [bbcView setRes:h :v];
- if ([bbcView window]) {
- NXRect bbcRt, winRt;
-
- [bbcView getBounds:&bbcRt];
- [[bbcView window] getBounds:&winRt];
- if (bbcRt.size.width > (winRt.size.width - 72.0))
- bbcRt.size.width = (winRt.size.width - 72.0);
- if (bbcRt.size.height > (winRt.size.height - 48.0))
- bbcRt.size.height = (winRt.size.height - 48.0);
- [scrollView sizeTo:bbcRt.size.height :bbcRt.size.width];
- }
- return self;
- }
- - stepForward
- {
- if (!dirFwd) [self reverse];
- return [self step];
- }
- - stepBackward
- {
- if (dirFwd) [self reverse];
- return [self step];
- }
- - step
- {
- int i,j, flag; // flag exists to check for extraordinary
- // conditions like collision on both corners
-
- if (state == NULL) return self;
- i = -1;
- while(++i < vres){
- j = -1;
- while(++j < hres){
- oldstate[i][j] = state[i][j];
- }
- }
- /* Phase 1: compute new velocities */
- i = vres;
- while(i-- > 0){
- j = -1;
- while(++j < hres){
- switch (state[i][j]) {
- case 'N':{ flag = 0;
- switch (state(i-1,j-1)){
- case 'E':
- case 'S':
- case 'O': { oldstate[i][j] = 'E';
- flag = 1;
- break;
- }
- default: break;
- }
- switch (state(i-1,j+1)){
- case 'W':
- case 'S':
- case 'O': { if (flag){
- oldstate[i][j] = 'S';
- } else {
- oldstate[i][j] = 'W';
- }
- break;
- }
- default: break;
- }
- break;}
- case 'S':{ flag = 0;
- switch (state(i+1,j-1)){
- case 'N':
- case 'E':
- case 'O': { oldstate[i][j] = 'E';
- flag = 1;
- break;
- }
- default: break;
- }
- switch (state(i+1,j+1)){
- case 'N':
- case 'W':
- case 'O': { if (flag){
- oldstate[i][j] = 'N';
- } else{
- oldstate[i][j] = 'W';
- }
- break;
- }
- default: break;
- }
- break;}
- case 'W':{ flag = 0;
- switch (state(i-1,j-1)){
- case 'E':
- case 'S':
- case 'O': { oldstate[i][j] = 'S';
- flag = 1;
- break;
- }
- default: break;
- }
- switch (state(i+1,j-1)){
- case 'E':
- case 'N':
- case 'O': { if (flag){
- oldstate[i][j] = 'E';
- } else{
- oldstate[i][j] = 'N';
- }
- break;
- }
- default: break;
- }
- break;}
- case 'E':{ flag = 0;
- switch (state(i-1,j+1)){
- case 'W':
- case 'S':
- case 'O': { oldstate[i][j] = 'S';
- flag = 1;
- break;
- }
- default: break;
- }
- switch (state(i+1,j+1)){
- case 'W':
- case 'N':
- case 'O': { if (flag){
- oldstate[i][j] = 'W';
- } else{
- oldstate[i][j] = 'N';
- }
- break;
- }
- default: break;
- }
- break;}
- }
- }
- }
-
- /* Phase 2: move balls */
- i = vres;
- while(i-- > 0){
- j = -1;
- while(++j < hres){
- switch (oldstate[i][j]) {
- case 'N':{ state[i][j] = ';';
- state(i-1,j) = 'N';
- break;}
- case 'S':{ state[i][j] = ';';
- state(i+1,j) = 'S';
- break;}
- case 'W':{ state[i][j] = ';';
- state(i,j-1) = 'W';
- break;}
- case 'E':{ state[i][j] = ';';
- state(i,j+1) = 'E';
- break;}
- }
- }
- }
- [bbcView display];
- return self;
- }
- - reverse
- {
- int i,j;
-
- if (state == NULL) {return self;}
- i = vres;
- while(i-- > 0){
- j = -1;
- while(++j < hres){
- switch (state[i][j]) {
- case 'N':{ state[i][j] = 'S';
- break;}
- case 'S':{ state[i][j] = 'N';
- break;}
- case 'W':{ state[i][j] = 'E';
- break;}
- case 'E':{ state[i][j] = 'W';
- break;}
- }
- }
- }
- dirFwd = !dirFwd;
- return self;
- }
-
- - writeRichText:(NXStream *)stream forView:view
- {
- if(!isLinked)
- NXPrintf(stream, "A %d %s", strlen(theName), theName);
- else NXPrintf(stream, "B %d %s", strlen(theName), theName);
- return self;
- }
- - readRichText:(NXStream *)stream forView:view
- {
- FILE *infile;
- int i,j;
- char c;
- char buf[MAXPATHLEN];
-
- if (!etDoc) etDoc = [view etDoc];
- [etDoc registerNotification:self];
- NXScanf(stream, "%c %d ", &isLinked, &i);
- isLinked -= 'A';
- if (i) NXRead(stream, buf, i);
- buf[i] = 0;
- theName = NXUniqueString(buf);
- if (isLinked && *buf && !access(buf,F_OK|R_OK)) {
- infile = fopen(buf,"r");
- fscanf(infile,"Hres %d Vres %d Reps %d\n",&hres,&vres,&i);
- state = malloc(vres* sizeof(char*));
- oldstate = malloc(vres* sizeof(char*));
- i = -1;
- while(++i < vres){
- j = -1;
- state[i] = malloc(hres*sizeof(char));
- oldstate[i] = malloc(hres*sizeof(char));
- while(++j < hres){
- fscanf(infile,"%c", &c);
- switch (c) {
- case 'O':{ state[i][j] = c;
- break;}
- case 'N':{ state[i][j] = c;
- break;}
- case 'S':{ state[i][j] = c;
- break;}
- case 'W':{ state[i][j] = c;
- break;}
- case 'E':{ state[i][j] = c;
- break;}
- case ';':
- case '.':
- default :{ state[i][j] = '.';
- break;}
- }
- }
- fscanf(infile,"%c", &c);
- }
- fclose(infile);
- [bbcView setRes:hres :vres];
- if ([bbcView window]) {
- NXRect bbcRt, winRt;
-
- [bbcView getBounds:&bbcRt];
- [[bbcView window] getBounds:&winRt];
- if (bbcRt.size.width > (winRt.size.width - 72.0))
- bbcRt.size.width = (winRt.size.width - 72.0);
- if (bbcRt.size.height > (winRt.size.height - 48.0))
- bbcRt.size.height = (winRt.size.height - 48.0);
- [scrollView sizeTo:bbcRt.size.height :bbcRt.size.width];
- }
- } else {
- sprintf(buf, "%s/%s.bbc", [[etDoc navinfo] path],theName);
- if (access(buf,F_OK|R_OK)) {
- state = malloc(vres * sizeof(char*));
- oldstate = malloc(vres * sizeof(char*));
- i = -1;
- while(++i < vres){
- state[i] = malloc(hres*sizeof(char));
- oldstate[i] = malloc(hres*sizeof(char));
- for(j=0; j<hres; j++) state[i][j] = '.';
- }
- [bbcView setRes:hres :vres];
- if ([bbcView window]) {
- NXRect bbcRt, winRt;
-
- [bbcView getBounds:&bbcRt];
- [[bbcView window] getBounds:&winRt];
- if (bbcRt.size.width > (winRt.size.width - 72.0))
- bbcRt.size.width = (winRt.size.width - 72.0);
- if (bbcRt.size.height > (winRt.size.height - 48.0))
- bbcRt.size.height = (winRt.size.height - 48.0);
- [scrollView sizeTo:bbcRt.size.height :bbcRt.size.width];
- }
- } else {
- infile = fopen(buf,"r");
- fscanf(infile,"Hres %d Vres %d Reps %d\n",&hres,&vres,&i);
- state = malloc(vres* sizeof(char*));
- oldstate = malloc(vres* sizeof(char*));
- i = -1;
- while(++i < vres){
- j = -1;
- state[i] = malloc(hres*sizeof(char));
- oldstate[i] = malloc(hres*sizeof(char));
- while(++j < hres){
- fscanf(infile,"%c", &c);
- switch (c) {
- case 'O':{ state[i][j] = c;
- break;}
- case 'N':{ state[i][j] = c;
- break;}
- case 'S':{ state[i][j] = c;
- break;}
- case 'W':{ state[i][j] = c;
- break;}
- case 'E':{ state[i][j] = c;
- break;}
- case ';':
- case '.':
- default :{ state[i][j] = '.';
- break;}
- }
- }
- fscanf(infile,"%c", &c);
- }
- fclose(infile);
- [bbcView setRes:hres :vres];
- if ([bbcView window]) {
- NXRect bbcRt, winRt;
-
- [bbcView getBounds:&bbcRt];
- [[bbcView window] getBounds:&winRt];
- if (bbcRt.size.width > (winRt.size.width - 72.0))
- bbcRt.size.width = (winRt.size.width - 72.0);
- if (bbcRt.size.height > (winRt.size.height - 48.0))
- bbcRt.size.height = (winRt.size.height - 48.0);
- [scrollView sizeTo:bbcRt.size.height :bbcRt.size.width];
- }
- }
- }
- return self;
- }
- - writeComponentToPath:(NXAtom)path inFormat:(int)theFormat
- {
- char thePath[MAXPATHLEN];
- int i,j;
- NXStream *stream;
-
- if (isLinked) return self;
- if (theFormat != ETFD_FORMAT) return self;
- sprintf(thePath,"%s/%s.bbc", path, theName);
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- NXPrintf(stream,"Hres %d Vres %d Reps %d\n",hres,vres, 1000);
- i = -1;
- while(++i < vres){
- j = -1;
- while(++j < hres){
- NXPutc(stream, (state[i][j] == ';' ? '.' : state[i][j]));
- }
- NXPutc(stream,'\n');
- }
- NXSaveToFile(stream, thePath);
- NXCloseMemory(stream, NX_FREEBUFFER);
- [etDoc registerComponent:NXUniqueString(rindex(thePath, '/')+1)];
- return self;
- }
- - writeASCII:(NXStream *)stream forView:view
- {
- NXPrintf(stream, "The BBC Simulation \"%s\"\n", theName);
- return self;
- }
- - writeASCIIRef:(NXStream *)stream forView:view
- {
- int i,j;
-
- NXPrintf(stream, "The BBC simulation \"%s\", in Jan's CS20 format:\n", theName);
- NXPrintf(stream,"Hres %d Vres %d Reps %d\n",hres,vres, 1000);
- i = -1;
- while(++i < vres){
- j = -1;
- while(++j < hres){
- NXPutc(stream, (state[i][j] == ';' ? '.' : state[i][j]));
- }
- NXPutc(stream,'\n');
- }
- return self;
- }
-
-
- @end